package com.jhf.youke.base.domain.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.jhf.youke.base.domain.converter.PermissionsSetConverter;
import com.jhf.youke.base.domain.gateway.PermissionsSetRepository;
import com.jhf.youke.base.domain.model.Do.PermissionsSetDo;
import com.jhf.youke.base.domain.model.dto.PermissionsSetMenuDto;
import com.jhf.youke.base.domain.model.po.PermissionsPo;
import com.jhf.youke.base.domain.model.po.PermissionsSetPo;
import com.jhf.youke.base.domain.model.vo.PermissionsSetVo;
import com.jhf.youke.core.common.localChace.LocalCache;
import com.jhf.youke.core.ddd.AbstractDomainService;
import com.jhf.youke.core.entity.PageQuery;
import com.jhf.youke.core.entity.Pagination;
import com.jhf.youke.core.utils.CacheUtils;
import com.jhf.youke.core.utils.Constant;
import com.jhf.youke.core.utils.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author RHJ
 * **/
@Service
public class PermissionsSetService extends AbstractDomainService<PermissionsSetRepository, PermissionsSetDo, PermissionsSetVo> {


    @Resource
    PermissionsSetConverter permissionsSetConverter;

    @Override
    public boolean update(PermissionsSetDo entity) {
        PermissionsSetPo permissionsSetPo = permissionsSetConverter.do2Po(entity);
        permissionsSetPo.preUpdate();
        return repository.update(permissionsSetPo);
    }

    @Override
    public boolean updateBatch(List<PermissionsSetDo> doList) {
        List<PermissionsSetPo> poList = permissionsSetConverter.do2PoList(doList);
        return repository.updateBatch(poList);
    }

    @Override
    public boolean delete(PermissionsSetDo entity) {
        PermissionsSetPo permissionsSetPo = permissionsSetConverter.do2Po(entity);
        return repository.delete(permissionsSetPo);
    }

    @Override
    public boolean deleteBatch(List<Long> idList) {
        return repository.deleteBatch(idList);
    }

    @Override
    public boolean insert(PermissionsSetDo entity) {
        PermissionsSetPo permissionsSetPo = permissionsSetConverter.do2Po(entity);
        permissionsSetPo.preInsert();
        return repository.insert(permissionsSetPo);
    }

    @Override
    public boolean insertBatch(List<PermissionsSetDo> doList) {
        List<PermissionsSetPo> poList = permissionsSetConverter.do2PoList(doList);
        poList = PermissionsSetPo.getInsertListId(poList);
        return repository.insertBatch(poList);
    }

    @Override
    public Optional<PermissionsSetVo> findById(Long id) {
        Optional<PermissionsSetPo> permissionsSetPo = repository.findById(id);
        PermissionsSetVo permissionsSetVo = permissionsSetConverter.po2Vo(permissionsSetPo.orElse(new PermissionsSetPo()));
        return Optional.ofNullable(permissionsSetVo);

    }

    @Override
    public boolean remove(Long id) {
        return repository.remove(id);
    }

    @Override
    public boolean removeBatch(List<Long> idList) {
        return repository.removeBatch(idList);
    }

    @Override
    public List<PermissionsSetVo> findAllMatching(PermissionsSetDo entity) {
        PermissionsSetPo permissionsSetPo = permissionsSetConverter.do2Po(entity);
        List<PermissionsSetPo> permissionsSetPoList = repository.findAllMatching(permissionsSetPo);
        return permissionsSetConverter.po2VoList(permissionsSetPoList);
    }


    @Override
    public Pagination<PermissionsSetVo> selectPage(PermissionsSetDo entity) {
        PermissionsSetPo permissionsSetPo = permissionsSetConverter.do2Po(entity);
        PageQuery<PermissionsSetPo> pageQuery = new PageQuery<>(permissionsSetPo, entity.getCurrentPage(), entity.getPageSize(), entity.getQuerySort());
        Pagination<PermissionsSetPo> pagination = repository.selectPage(pageQuery);
        return new Pagination<PermissionsSetVo>(pagination.getPageNum(), pagination.getPageSize(), pagination.getTotalSize(),
                permissionsSetConverter.po2VoList(pagination.getList()));
    }

    public Pagination<PermissionsSetVo> getWhiteList(PermissionsSetDo entity){
        PermissionsSetPo userPo = permissionsSetConverter.do2Po(entity);
        PageQuery<PermissionsSetPo> pageQuery = new PageQuery<>(userPo,entity.getCurrentPage(), entity.getPageSize(), entity.getQuerySort());
        Pagination<PermissionsSetPo> pagination = repository.getWhiteList(pageQuery);
        return new Pagination<PermissionsSetVo>(pagination.getPageNum(),pagination.getPageSize(),pagination.getTotalSize(),
                permissionsSetConverter.po2VoList(pagination.getList()));
    }

    /**
     * 返回的MAP，key值为url，网关添加日志时使用,存入本地缓存
     *
     * @param dto
     * @return
     * @throws Exception
     */
    public Map<String, Object> getAllListToMap(PermissionsSetDo dto) {
        String key = "all_permissions_map";
        Map<String, Object> data = new HashMap<>(8);
        Object menuObject = CacheUtils.get(key);
        if (ObjectUtil.isEmpty(menuObject)) {
            List<PermissionsSetVo> list = findAllMatching(dto);
            Map<String, List<PermissionsSetVo>> setVoMap = list.stream().collect(Collectors.groupingBy(PermissionsSetVo::getUrl));
            BeanUtil.copyProperties(setVoMap, data, true);
            Map<String, Object> map = new HashMap<>(8);
            map.put("key", key);
            map.put("value", JSONUtil.toJsonStr(data));
            map.put("time", 60 * 60 * 24);
            CacheUtils.setByJson(map);
        } else {
            data = BeanUtil.beanToMap(JSONUtil.parseObj(menuObject), false, true);
        }
        return data;
    }

    /**
     * 根据菜单ID查询菜单的权限
     *
     * @param menuId
     * @return
     */
    public List<PermissionsSetVo> getListByMenuId(Long menuId) {
        List<PermissionsSetPo> poList = repository.getListByMenuId(menuId);
        return permissionsSetConverter.po2VoList(poList);
    }

    /**
     * 所有菜单的权限
     *
     * @return
     */
    public List<PermissionsSetPo> getAllMenuSetList() {
        List<PermissionsSetPo> poList = repository.getAllMenuSetList();
        return poList;
    }


    public List<PermissionsSetPo> getAllMenuByCache(){
        String key = "all_menu_permissions";
        List<PermissionsSetPo> permissionsSetPoList = (List<PermissionsSetPo>) LocalCache.get(key);
        if(permissionsSetPoList == null){
            permissionsSetPoList = getAllMenuSetList();
            LocalCache.put(key, permissionsSetPoList, 20 * 60 * 60);
        }
        return permissionsSetPoList;
    }

    public Map<String,Long> getAllMenuPermissionsToMap(){
        List<PermissionsSetPo> menuPoList = getAllMenuByCache();
        return menuPoList.stream().collect(Collectors.toMap(PermissionsSetPo::getPermissionCode, PermissionsSetPo::getBizId, (entity1, entity2) -> entity1));
    }


    /**
     * 用户角色的所有权限
     *
     * @param userId
     * @return
     */
    public List<PermissionsSetVo> getUrlListByUser(Long userId) {
        List<PermissionsSetPo> poList = repository.getUrlListByUser(userId);
        return permissionsSetConverter.po2VoList(poList);
    }


    /**
     * 更新菜单关联的按钮权限
     *
     * @param dto
     */
    public void updateMenuSet(PermissionsSetMenuDto dto) {
        List<PermissionsSetPo> poList = repository.getListByMenu(dto.getMenuId());
        List<Long> ids = new ArrayList<>();
        for (PermissionsSetPo item : poList) {
            ids.add(item.getId());
        }
        if (ids.size() > 0) {
            repository.deleteBatch(ids);
        }
        if (dto.getPermissionIdList().size() > 0) {
            List<PermissionsSetPo> saveList = new ArrayList<>();
            for (String permissionId : dto.getPermissionIdList()) {
                PermissionsSetPo set = new PermissionsSetPo();
                set.setType(2);
                set.setBizId(dto.getMenuId());
                set.setPermissionId(StringUtils.toLong(permissionId));
                set.preInsert();
                saveList.add(set);
            }
            repository.insertBatch(saveList);
        }
    }

    /**
     * 获取角色的权限ids
     *
     * @param roleId
     * @return
     */
    public List<String> getListByRole(Long roleId) {
        PermissionsSetPo permissionsSetPo = new PermissionsSetPo();
        permissionsSetPo.setBizId(roleId);
        permissionsSetPo.setType(1);
        List<PermissionsSetPo> poList = repository.findAllMatching(permissionsSetPo);
        List<String> ids = new ArrayList<>();
        for (PermissionsSetPo item : poList) {
            ids.add(item.getPermissionId().toString());
        }
        return ids;
    }

    /**
     * 更新角色关联的权限
     */
    public void updateRoleSet(Long roleId, List<Map<String,Object>> permissionList) {
        PermissionsSetPo poParam = new PermissionsSetPo();
        poParam.setType(1);
        poParam.setBizId(roleId);
        List<PermissionsSetPo> poList = repository.findAllMatching(poParam);
        List<Long> ids = new ArrayList<>();
        for (PermissionsSetPo item : poList) {
            ids.add(item.getId());
        }
        if (ids.size() > 0) {
            repository.deleteBatch(ids);
        }
        if (permissionList.size() > 0) {
            List<PermissionsSetPo> saveList = new ArrayList<>();
            for (Map<String,Object> permissionItem : permissionList) {
                PermissionsSetPo set = new PermissionsSetPo();
                set.setType(1);
                set.setBizId(roleId);
                set.setPermissionId(StringUtils.toLong(permissionItem.get("id")));
                set.setPermissionCode(StringUtils.chgNull(permissionItem.get("code")));
                set.preInsert();
                saveList.add(set);
            }
            repository.insertBatch(saveList);
        }
    }

    public List<String> getPermissionCodeListByUser(Long userId) {
        List<String> codeList = new ArrayList<>();
        if (Constant.SUPER_ADMINISTRATOR.equals(userId)){
            //超级管理员默认有所有按钮权限
            codeList.add("*:*:*");
            return codeList;
        }
        List<PermissionsPo> poList = repository.getListByUser(userId);
        for (PermissionsPo item : poList) {
            if(item.getType() != 1) {
                codeList.add(item.getCode());
            }
        }
        return codeList;
    }

    public Set<Long> getMenuIdsByUser(Set<String> getAllMenuPermissionsToMap) {
        Map<String, Long> allMenuPermissions = getAllMenuPermissionsToMap();
        Set<Long> menuIds = new HashSet<>(256);
        getAllMenuPermissionsToMap.forEach(code ->{
            menuIds.add(allMenuPermissions.get(code));
        });
        return menuIds;

    }
}

